package com.b511.swpu.cementbackend.util;

import com.b511.swpu.cementbackend.dto.output.TreeOutputDto;
import com.b511.swpu.cementbackend.entity.Tree;
import org.springframework.beans.BeanUtils;

import java.util.*;

public class TreeUtil<T extends Tree> {

    public  List<TreeOutputDto> getTree(List<T> trees) {
        List<TreeOutputDto> result = new ArrayList<>();
        Map<String, TreeOutputDto> treeDict = getTreeDict(trees);
        TreeSet<Integer> treeCodeLength = getTreeCodeLength(trees);
        trees.forEach(tree -> {
            String code = tree.getCode();
            if (treeCodeLength.first().equals(code.length())) {
                result.add(treeDict.get(code));
            } else {
                TreeOutputDto child = treeDict.get(code);
                Integer parentCodeLength = treeCodeLength.lower(code.length());
                String parentCode = code.substring(0, parentCodeLength);
                TreeOutputDto parent = treeDict.get(parentCode);
                addChild(parent, child);
            }
        });
        return result;
    }

    private static void addChild(TreeOutputDto parent, TreeOutputDto child) {
        if (null != parent.getChildren()) {
            parent.getChildren().add(child);
        } else {
            List<TreeOutputDto> list = new ArrayList<>();
            list.add(child);
            parent.setChildren(list);
        }
    }

    private Map<String, TreeOutputDto> getTreeDict(List<T> trees) {
        Map<String, TreeOutputDto> result = new HashMap<>();
        trees.forEach(tree -> {
            TreeOutputDto treeOutputDto = new TreeOutputDto();
            BeanUtils.copyProperties(tree, treeOutputDto);
            result.put(tree.getCode(), treeOutputDto);
        });
        return result;
    }

    private TreeSet<Integer> getTreeCodeLength(List<T> trees) {
        TreeSet<Integer> result = new TreeSet<>();
        trees.forEach(tree -> {
            result.add(tree.getCode().length());
        });
        return result;
    }
}
